#ifndef _B_PLUS_TREE_NODES_STORAGE_HPP__
#define _B_PLUS_TREE_NODES_STORAGE_HPP__ 1
#include <BPlusNodeLeaf.hpp>
#include <BPlusTreeNodeLeafData.hpp>
#include <Storage.hpp>
/**
 *
 */

using namespace MAIL;
namespace FTSS {
	class BPlusTreeNodeStorage : Storage{
		public : 
			/**
			* @brief Constructor
			*/
			BPlusTreeNodeStorage(CCHAR_P storage_name, CCHAR_P empty_blocks) : 
				Storage(storage_name, empty_blocks){
					INT_64 *data_64 = (INT_64 *) storage_data_mmap;
					data_64[2] = 0; // root id
					data_64[3] = 0; // tree_size
					data_64[4] = 0; // tree_width
			};
			
			/**
			* @brief Get Node By Id from HDD storage
			* @return pointer to restored node or NULL if not success
			*/	
			template <typename T, INT_64 TreeWidth>	
			BPlusNode<T, TreeWidth>* GetNodeById(INT_32 node_id){
				if (node_id < length_data){
					BPlusNode<BPlusTreeNodeData, TreeWidth> *pRes = new BPlusNode<BPlusTreeNodeData, TreeWidth>();
					CHAR_P src = storage_data_mmap + 2 * sizeof(INT_64) + 
									node_id * sizeof(BPlusNode<BPlusTreeNodeData, TreeWidth>);
					if (memcpy(pRes,
					    	   src,
				      	       	   sizeof(BPlusNode<BPlusTreeNodeData, TreeWidth>)) != pRes){
							throw UnixException(errno, "memcpy in get node by id\n");
					}
					return pRes;
				}
				return NULL;
			}

			
			template <typename T, INT_64 TreeWidth>
			INT_32 DumpNode(BPlusNodeType *pNode){
				return DumpNode((BPlusNode<T, TreeWidth> *)pNode);
			}

			/**	
			 * @brief DumpNode to white space of storage or to the end of file
			 * and generate node id and return it if node has node_id == 0
			 * else dump node to the node_id space
			 * @param pNode node to dump
			 * @return dumped node id
		 	*/
			template <typename T, INT_64 TreeWidth>
			INT_32 DumpNode(BPlusNode<T, TreeWidth> *pNode){
				INT_32 current_node_id;
				if (pNode != NULL && pNode->id != 0){
					current_node_id = pNode->id;
					if (current_node_id > length_data) length_data = current_node_id;
				} else if (length_stack > 0){
					current_node_id = vector_data_mmap[length_stack + 1];
					--length_stack;
				} else {
					current_node_id = length_data;
					++length_data;
				}
				//remmaping and increment filesize
				if( sizeof(BPlusNode<BPlusTreeNodeData, TreeWidth>) * (current_node_id + 1) + 
										2 * ((INT_32)sizeof(INT_64)) >= size_storage_nodes)
				{
					if (ReMMAP(data_storageHandler) != 0)
						throw UnixException(errno, "remmap nodes sotrage fails");
				}

				pNode->id = current_node_id;
				if (pNode != NULL){
					// dst pointer calculate
					CHAR_P dst = storage_data_mmap + 2 * sizeof(INT_64) + 
								current_node_id * sizeof(BPlusNode<BPlusTreeNodeData, TreeWidth>);
					if (memcpy(dst,
						   pNode,
						   sizeof(BPlusNode<BPlusTreeNodeData, TreeWidth>)) != dst){
						throw UnixException(errno, "memcpy in dump node \n");
					}
				}
				return current_node_id;
			}

			/**
			* @brief delete node from HDD storage
			* @return 0 if success, -1 if something wrong
			*/	
			INT_32 DeleteNode(INT_32 node_id){
				// remmapping need
                 		if (length_stack + 2 >= (size_vector_file / sizeof(INT_64))){
		                        if (ReMMAP(vector_empty_blocksHandler) != 0)
                		                throw UnixException(errno, "remmap vector empty block fails");
                		}               
				// to white space vector add
		                if (node_id < length_data){
                		        vector_data_mmap[length_stack + 2] = node_id;
        	        		++length_stack;
		                        return 0;
        		        }       
	        	        return -1;
       			} 

			/**
			* @brief dump to HDD storage root id 
			* @param root_id root id to dump
			*/
			void DumpRootId(INT_64 root_id){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				data_64[2] = root_id;
				return;
			}

			/**
			* @brief restore from HDD storage root id meta information
			* @return root id
			*/
			INT_64 RestoreRootId(){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				return data_64[2];
			}

			/**
			* @brief dump to HDD storage tree size 
			* @param tree_size tree size to dump
			*/
			void DumpTreeSize(INT_64 tree_size){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				data_64[3] = tree_size;
				return;
			}

			/**
			* @brief restore from HDD storage tree size meta information
			* @return tree size
			*/
			INT_64 RestoreTreeSize(){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				return data_64[3];
			}

			/**
			* @brief dump to HDD storage tree width
			* @param tree_width tree width to dump
			*/
			void DumpTreeWidth(INT_64 tree_width){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				data_64[4] = tree_width;
				return;
			}

			/**
			* @brief restore from HDD storage tree width met information
			* @return tree width
			*/
			INT_64 RestoreTreeWidth(){
				INT_64 *data_64 = (INT_64 *)vector_data_mmap;
				return data_64[4];
			}

			/**
			* @Destructor 
			*/
			virtual ~BPlusTreeNodeStorage() throw() {};
	};
}
#endif
